"""
桌面宠物主程序
功能：透明悬浮窗口 + GIF显示 + 拖拽 + 放松游戏 + 指令交互 + 日程管理 + 换皮肤
"""
import tkinter as tk
from tkinter import Menu, Text, Checkbutton, IntVar, Scrollbar
from PIL import Image, ImageTk, ImageSequence
import random
import time
import json
import os
from timer_manager import TimerManager
import requests
import threading

# 硅基流动 API配置
SILICONFLOW_API_KEY = "sk-ccgdekzhyxpwxsqhqxdvgifddwrrietidornsqddgumsiqyn"
SILICONFLOW_API_URL = "https://api.siliconflow.cn/v1/chat/completions"
SILICONFLOW_MODEL = "deepseek-ai/DeepSeek-V2.5"
SYSTEM_PROMPT = "你是一只可爱的桌面宠物，说话软萌活泼，带点小调皮，回应要简短（不超过50字）。当用户说烦恼时，要温柔安慰；说开心时，要跟着一起开心~"

# 可调参数
WORK_TIME = 180     # 工作时长（秒），3分钟后触发游戏
GAME_TIME = 60      # 游戏时长（秒）
MOVE_SPEED = 3      # 游戏中移动速度（像素/帧）
MOVE_INTERVAL = 30  # 移动刷新间隔（毫秒）
ASSETS_DIR = r"D:\vue01\desktop-pet\assets"  # 皮肤资源目录
DEFAULT_SKIN = "pet.gif"  # 默认皮肤文件名

# 窗口样式配置
WINDOW_BG = '#f8f9fa'
TITLE_BG = '#e3f2fd'
TITLE_FG = '#1976d2'
INPUT_BG = '#ffffff'
BUTTON_BG = '#42a5f5'
SUCCESS_BG = '#66bb6a'
CANCEL_BG = '#bdbdbd'

# 关怀语列表
CARE_MESSAGES = [
    "久坐后可以出去晒晒太阳呀～",
    "眼睛累啦，看看远处5分钟吧！",
    "活动一下肩膀，别让颈椎抗议～",
    "喝口水休息下，等下继续加油呀！"
]

# 预设回应库
JOKES = [
    "为什么程序员总是分不清万圣节和圣诞节？因为 Oct 31 == Dec 25！",
    "从前有个Bug，它走进了一家酒吧...然后整个程序崩溃了。",
    "为什么Python程序员不喜欢大自然？因为外面有太多的bugs！"
]

SONGS = [
    "🎵 写代码写到手抽筋，Debug调到眼发昏～ 🎵",
    "🎵 你是我的小呀小宠物，怎么爱你都不嫌多～ 🎵",
    "🎵 阳光彩虹小白马，滴滴答滴滴答～ 🎵"
]

ENCOURAGEMENTS = [
    "加油！你是最棒的！💪",
    "今天也要元气满满哦～ ✨",
    "相信自己，你可以的！�",
    "休息一下，继续冲鸭！🦆"
]


class DesktopPet:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("桌面宠物")
        
        # 窗口设置：无边框、置顶、透明
        self.root.overrideredirect(True)
        self.root.attributes('-topmost', True)
        self.root.attributes('-transparentcolor', 'white')
        self.root.config(bg='white')
        
        # 获取屏幕尺寸
        self.screen_width = self.root.winfo_screenwidth()
        self.screen_height = self.root.winfo_screenheight()
        
        # 初始位置
        self.root.geometry('+500+400')
        
        # 创建标签显示GIF
        self.label = tk.Label(self.root, bg='white')
        self.label.pack()
        
        # 皮肤相关变量
        self.current_skin = DEFAULT_SKIN
        self.frames = []
        self.current_frame = 0
        self.load_gif(os.path.join(ASSETS_DIR, self.current_skin))
        
        # 拖拽相关变量
        self.drag_start_x = 0
        self.drag_start_y = 0
        
        # 游戏相关变量
        self.in_game = False
        self.game_start_time = 0
        self.velocity_x = MOVE_SPEED
        self.velocity_y = MOVE_SPEED
        self.game_move_id = None
        
        # 气泡相关变量
        self.bubble_window = None
        self.bubble_close_id = None
        
        # 日程数据文件路径
        self.todo_file = "data/todo_list.json"
        self.ensure_data_dir()
        
        # 绑定事件
        self.label.bind('<Button-1>', self.start_drag)
        self.label.bind('<B1-Motion>', self.on_drag)
        self.label.bind('<Button-3>', self.show_menu)
        self.label.bind('<Double-Button-1>', self.run_away)  # 双击跑开
        
        # 绑定快捷键 Ctrl+Alt+P
        self.root.bind_all('<Control-Alt-p>', lambda e: self.show_command_input())
        
        # 初始化时间管理器
        self.timer = TimerManager(WORK_TIME, self.start_game)
        self.timer.start()
        
        # 开始播放GIF
        self.animate_gif()
        
        # 启动计时器检查
        self.timer.check_time(self.root)
    
    def ensure_data_dir(self):
        """确保data目录存在，并清空旧日程"""
        os.makedirs("data", exist_ok=True)
        with open(self.todo_file, 'w', encoding='utf-8') as f:
            json.dump([], f, ensure_ascii=False)
    
    def get_safe_window_position(self, width, height, offset_x=150, offset_y=0):
        """计算安全的窗口位置，确保窗口完整显示在屏幕内"""
        pet_x = self.root.winfo_x()
        pet_y = self.root.winfo_y()
        
        win_x = pet_x + offset_x
        win_y = pet_y + offset_y
        
        if win_x + width > self.screen_width:
            win_x = pet_x - width - 20
            if win_x < 0:
                win_x = self.screen_width - width - 10
        if win_x < 0:
            win_x = 10
        if win_y + height > self.screen_height:
            win_y = self.screen_height - height - 10
        if win_y < 0:
            win_y = 10
        
        return win_x, win_y
    
    def load_gif(self, gif_path):
        """加载GIF的所有帧"""
        try:
            self.frames = []
            img = Image.open(gif_path)
            for frame in ImageSequence.Iterator(img):
                frame = frame.convert('RGBA')
                photo = ImageTk.PhotoImage(frame)
                self.frames.append(photo)
            print(f"成功加载皮肤: {os.path.basename(gif_path)}")
        except Exception as e:
            print(f"加载GIF失败: {e}")
            if not self.frames:
                self.root.quit()
    
    def animate_gif(self):
        """循环播放GIF动画"""
        if self.frames:
            self.label.config(image=self.frames[self.current_frame])
            self.current_frame = (self.current_frame + 1) % len(self.frames)
        self.root.after(100, self.animate_gif)

    # ==================== 拖拽功能 ====================
    
    def start_drag(self, event):
        if self.in_game:
            self.on_click_in_game()
        else:
            self.drag_start_x = event.x
            self.drag_start_y = event.y
    
    def on_drag(self, event):
        if not self.in_game:
            x = self.root.winfo_x() + event.x - self.drag_start_x
            y = self.root.winfo_y() + event.y - self.drag_start_y
            self.root.geometry(f'+{x}+{y}')
    
    def run_away(self, event):
        """双击时桌宠跑开"""
        if self.in_game:
            return
        
        # 随机选择一个新位置（远离当前位置）
        current_x = self.root.winfo_x()
        current_y = self.root.winfo_y()
        
        # 计算新位置（至少移动200像素）
        direction_x = random.choice([-1, 1])
        direction_y = random.choice([-1, 1])
        
        new_x = current_x + direction_x * random.randint(200, 400)
        new_y = current_y + direction_y * random.randint(150, 300)
        
        # 确保不超出屏幕
        new_x = max(0, min(new_x, self.screen_width - 100))
        new_y = max(0, min(new_y, self.screen_height - 100))
        
        # 快速移动到新位置（动画效果）
        self.animate_run_away(current_x, current_y, new_x, new_y)
    
    def animate_run_away(self, start_x, start_y, end_x, end_y, steps=10, current_step=0):
        """跑开的动画效果"""
        if current_step >= steps:
            # 跑完后显示气泡
            reactions = ["哎呀别戳我啦～ 😣", "抓不到我～ 🏃", "嘻嘻跑掉啦～ 😝", "你追不上我的！✨"]
            self.show_bubble(random.choice(reactions), 2000)
            return
        
        # 计算当前位置
        progress = (current_step + 1) / steps
        current_x = int(start_x + (end_x - start_x) * progress)
        current_y = int(start_y + (end_y - start_y) * progress)
        
        self.root.geometry(f'+{current_x}+{current_y}')
        
        # 继续下一帧
        self.root.after(20, lambda: self.animate_run_away(start_x, start_y, end_x, end_y, steps, current_step + 1))
    
    # ==================== 右键菜单 ====================
    
    def show_menu(self, event):
        menu = Menu(self.root, tearoff=0)
        menu.add_command(label="发送指令", command=self.show_command_input)
        menu.add_command(label="新建日程", command=self.show_new_todo)
        menu.add_command(label="管理日程", command=self.show_manage_todo)
        menu.add_command(label="换皮肤", command=self.show_skin_selector)
        menu.add_separator()
        menu.add_command(label="退出", command=self.quit_app)
        menu.post(event.x_root, event.y_root)
    
    def quit_app(self):
        self.root.quit()
    
    # ==================== 气泡组件 ====================
    
    def show_bubble(self, text, duration=5000):
        if self.bubble_window:
            try:
                self.bubble_window.destroy()
            except:
                pass
        if self.bubble_close_id:
            self.root.after_cancel(self.bubble_close_id)
        
        self.bubble_window = tk.Toplevel(self.root)
        self.bubble_window.overrideredirect(True)
        self.bubble_window.attributes('-topmost', True)
        self.bubble_window.config(bg='#fff9c4')
        
        shadow_frame = tk.Frame(self.bubble_window, bg='#e0e0e0')
        shadow_frame.pack(padx=2, pady=2)
        
        frame = tk.Frame(shadow_frame, bg='#fff9c4')
        frame.pack()
        
        label = tk.Label(frame, text=text, bg='#fff9c4', fg='#424242', 
                        font=('微软雅黑', 10), wraplength=250)
        label.pack(padx=20, pady=12)
        label.bind('<Button-1>', lambda e: self.close_bubble())
        
        pet_x = self.root.winfo_x()
        pet_y = self.root.winfo_y()
        self.bubble_window.update_idletasks()
        bubble_width = self.bubble_window.winfo_width()
        bubble_x = pet_x + (self.root.winfo_width() - bubble_width) // 2
        bubble_y = pet_y - self.bubble_window.winfo_height() - 10
        self.bubble_window.geometry(f'+{bubble_x}+{bubble_y}')
        self.bubble_close_id = self.root.after(duration, self.close_bubble)
    
    def close_bubble(self):
        if self.bubble_window:
            try:
                self.bubble_window.destroy()
            except:
                pass
            self.bubble_window = None
        if self.bubble_close_id:
            self.root.after_cancel(self.bubble_close_id)
            self.bubble_close_id = None
    
    # ==================== 指令输入窗口 ====================
    
    def show_command_input(self):
        input_win = tk.Toplevel(self.root)
        input_win.overrideredirect(True)
        input_win.attributes('-topmost', True)
        input_win.config(bg=WINDOW_BG)
        
        win_x, win_y = self.get_safe_window_position(320, 160)
        input_win.geometry(f'320x160+{win_x}+{win_y}')
        
        shadow = tk.Frame(input_win, bg='#d0d0d0')
        shadow.pack(fill='both', expand=True, padx=3, pady=3)
        main_frame = tk.Frame(shadow, bg=WINDOW_BG)
        main_frame.pack(fill='both', expand=True)
        
        title_frame = tk.Frame(main_frame, bg=TITLE_BG, height=40)
        title_frame.pack(fill='x')
        title_frame.pack_propagate(False)
        tk.Label(title_frame, text="💬 发送指令", bg=TITLE_BG, fg=TITLE_FG,
                font=('微软雅黑', 11, 'bold')).pack(side='left', padx=15, pady=10)
        tk.Button(title_frame, text="✕", bg=TITLE_BG, fg=TITLE_FG, relief='flat',
                 font=('微软雅黑', 12, 'bold'), command=input_win.destroy, 
                 cursor='hand2').pack(side='right', padx=10)
        
        entry_frame = tk.Frame(main_frame, bg=WINDOW_BG)
        entry_frame.pack(pady=12, padx=20, fill='x')
        entry = tk.Entry(entry_frame, font=('微软雅黑', 11), relief='solid', bg=INPUT_BG)
        entry.pack(fill='x', pady=8, ipady=5)
        entry.focus()
        
        def on_confirm():
            cmd = entry.get().strip()
            if cmd:
                self.handle_command(cmd)
            input_win.destroy()
        
        tk.Button(entry_frame, text="发送", command=on_confirm, bg=SUCCESS_BG, fg='white',
                 font=('微软雅黑', 10, 'bold'), relief='flat', padx=30, pady=7, 
                 cursor='hand2').pack(pady=10)
        entry.bind('<Return>', lambda e: on_confirm())
    
    # ==================== 指令处理 ====================
    
    def handle_command(self, text):
        """处理用户指令，优先处理特殊指令，其他交给豆包AI"""
        text_lower = text.lower()
        
        # 特殊指令：提醒喝水
        if "提醒" in text_lower and "喝水" in text_lower:
            self.show_bubble("好的！5分钟后提醒你喝水～")
            self.root.after(5*60*1000, lambda: self.show_bubble("该喝水啦～ 💧"))
            return
        
        # 特殊指令：完成任务
        if "完成了" in text_lower or "做完了" in text_lower:
            task = text.replace("完成了", "").replace("做完了", "").strip()
            if self.mark_todo_done_by_name(task):
                self.show_bubble(f"太棒啦！【{task}】搞定～", 6000)
            else:
                self.show_bubble("没找到这个任务哦～")
            return
        
        # 其他指令交给豆包AI处理
        self.show_bubble("思考中... 🤔", 10000)
        
        # 在后台线程调用API，避免界面卡顿
        def call_api():
            response = self.call_ai_api(text)
            # 回到主线程更新UI
            self.root.after(0, lambda: self.show_bubble(response, 8000))
        
        thread = threading.Thread(target=call_api, daemon=True)
        thread.start()
    
    def call_ai_api(self, user_message):
        """调用硅基流动API获取回复"""
        try:
            headers = {
                "Content-Type": "application/json",
                "Authorization": f"Bearer {SILICONFLOW_API_KEY}"
            }
            
            data = {
                "model": SILICONFLOW_MODEL,
                "messages": [
                    {
                        "role": "system",
                        "content": SYSTEM_PROMPT
                    },
                    {
                        "role": "user",
                        "content": user_message
                    }
                ],
                "max_tokens": 100,
                "temperature": 0.7
            }
            
            response = requests.post(SILICONFLOW_API_URL, headers=headers, json=data, timeout=15)
            
            if response.status_code == 200:
                result = response.json()
                reply = result["choices"][0]["message"]["content"].strip()
                # 确保回复不超过60个字
                if len(reply) > 60:
                    reply = reply[:60] + "..."
                return reply
            else:
                print(f"硅基流动API错误: {response.status_code} - {response.text}")
                return random.choice(ENCOURAGEMENTS)
                
        except Exception as e:
            print(f"调用硅基流动API失败: {e}")
            return random.choice(ENCOURAGEMENTS)

    # ==================== 日程管理 ====================
    
    def load_todos(self):
        try:
            with open(self.todo_file, 'r', encoding='utf-8') as f:
                return json.load(f)
        except:
            return []
    
    def save_todos(self, todos):
        with open(self.todo_file, 'w', encoding='utf-8') as f:
            json.dump(todos, f, ensure_ascii=False, indent=2)
    
    def show_new_todo(self):
        todo_win = tk.Toplevel(self.root)
        todo_win.overrideredirect(True)
        todo_win.attributes('-topmost', True)
        todo_win.config(bg=WINDOW_BG)
        
        win_x, win_y = self.get_safe_window_position(380, 340)
        todo_win.geometry(f'380x340+{win_x}+{win_y}')
        
        shadow = tk.Frame(todo_win, bg='#d0d0d0')
        shadow.pack(fill='both', expand=True, padx=3, pady=3)
        main_frame = tk.Frame(shadow, bg=WINDOW_BG)
        main_frame.pack(fill='both', expand=True)
        
        title_frame = tk.Frame(main_frame, bg=TITLE_BG, height=40)
        title_frame.pack(fill='x')
        title_frame.pack_propagate(False)
        tk.Label(title_frame, text="📝 新建日程", bg=TITLE_BG, fg=TITLE_FG,
                font=('微软雅黑', 11, 'bold')).pack(side='left', padx=15, pady=10)
        tk.Button(title_frame, text="✕", bg=TITLE_BG, fg=TITLE_FG, relief='flat',
                 font=('微软雅黑', 12, 'bold'), command=todo_win.destroy,
                 cursor='hand2').pack(side='right', padx=10)
        
        input_frame = tk.Frame(main_frame, bg=WINDOW_BG)
        input_frame.pack(pady=15, padx=20, fill='both', expand=True)
        tk.Label(input_frame, text="输入待办事项（每行一个）：", bg=WINDOW_BG, 
                fg='#616161', font=('微软雅黑', 9)).pack(anchor='w', pady=(0,5))
        
        text_widget = Text(input_frame, height=7, font=('微软雅黑', 10), 
                          relief='solid', bg=INPUT_BG)
        text_widget.pack(fill='x', pady=5)
        
        remind_var = IntVar(value=1)
        Checkbutton(input_frame, text="需要提醒", variable=remind_var, bg=WINDOW_BG,
                   fg='#616161', font=('微软雅黑', 9), cursor='hand2').pack(anchor='w', pady=8)
        
        def on_save():
            content = text_widget.get('1.0', 'end').strip()
            if not content:
                self.show_bubble("请输入至少一个待办事项～")
                return
            lines = [l.strip() for l in content.split('\n') if l.strip()]
            todos = self.load_todos()
            for line in lines:
                todos.append({'task': line, 'done': False, 'remind': remind_var.get()==1,
                             'created_at': time.strftime('%Y-%m-%d %H:%M:%S')})
            self.save_todos(todos)
            todo_win.destroy()
            if lines:
                self.show_bubble(f"今天要做的第一件事是【{lines[0]}】，开始吧！", 6000)
        
        tk.Button(input_frame, text="保存", command=on_save, bg=SUCCESS_BG, fg='white',
                 font=('微软雅黑', 10, 'bold'), relief='flat', padx=35, pady=8,
                 cursor='hand2').pack(pady=10)
    
    def show_manage_todo(self):
        todos = self.load_todos()
        manage_win = tk.Toplevel(self.root)
        manage_win.overrideredirect(True)
        manage_win.attributes('-topmost', True)
        manage_win.config(bg=WINDOW_BG)
        
        win_x, win_y = self.get_safe_window_position(420, 370)
        manage_win.geometry(f'420x370+{win_x}+{win_y}')
        
        shadow = tk.Frame(manage_win, bg='#d0d0d0')
        shadow.pack(fill='both', expand=True, padx=3, pady=3)
        main_frame = tk.Frame(shadow, bg=WINDOW_BG)
        main_frame.pack(fill='both', expand=True)
        
        title_frame = tk.Frame(main_frame, bg=TITLE_BG, height=40)
        title_frame.pack(fill='x')
        title_frame.pack_propagate(False)
        tk.Label(title_frame, text="📋 管理日程", bg=TITLE_BG, fg=TITLE_FG,
                font=('微软雅黑', 11, 'bold')).pack(side='left', padx=15, pady=10)
        tk.Button(title_frame, text="✕", bg=TITLE_BG, fg=TITLE_FG, relief='flat',
                 font=('微软雅黑', 12, 'bold'), command=manage_win.destroy,
                 cursor='hand2').pack(side='right', padx=10)
        
        list_frame = tk.Frame(main_frame, bg=WINDOW_BG, height=240)
        list_frame.pack(pady=15, padx=20, fill='x')
        list_frame.pack_propagate(False)
        
        canvas = tk.Canvas(list_frame, bg=INPUT_BG, relief='solid', borderwidth=1)
        scrollbar = Scrollbar(list_frame, orient='vertical', command=canvas.yview)
        scrollable_frame = tk.Frame(canvas, bg=INPUT_BG)
        scrollable_frame.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
        canvas.create_window((0, 0), window=scrollable_frame, anchor='nw')
        canvas.configure(yscrollcommand=scrollbar.set)
        canvas.pack(side='left', fill='both', expand=True)
        scrollbar.pack(side='right', fill='y')
        
        check_vars = []
        if not todos:
            tk.Label(scrollable_frame, text="暂无待办事项～", bg=INPUT_BG, fg='#9e9e9e',
                    font=('微软雅黑', 10)).pack(pady=30)
        else:
            for i, todo in enumerate(todos):
                var = IntVar(value=1 if todo['done'] else 0)
                check_vars.append((var, i))
                status = "✓ " if todo['done'] else ""
                fg = '#9e9e9e' if todo['done'] else '#424242'
                Checkbutton(scrollable_frame, text=f"{status}{todo['task']}", variable=var,
                           bg=INPUT_BG, fg=fg, font=('微软雅黑', 10), anchor='w',
                           cursor='hand2').pack(fill='x', padx=15, pady=5)
        
        def on_confirm():
            todos = self.load_todos()
            completed = []
            for var, idx in check_vars:
                if var.get() == 1 and not todos[idx]['done']:
                    todos[idx]['done'] = True
                    completed.append(todos[idx]['task'])
            self.save_todos(todos)
            manage_win.destroy()
            if completed:
                self.show_bubble(f"太棒啦！【{completed[0]}】搞定～", 6000)
        
        btn_frame = tk.Frame(main_frame, bg=WINDOW_BG)
        btn_frame.pack(pady=15)
        tk.Button(btn_frame, text="确认完成", command=on_confirm, bg=SUCCESS_BG, fg='white',
                 font=('微软雅黑', 10, 'bold'), relief='flat', padx=30, pady=8,
                 cursor='hand2').pack(side='left', padx=8)
        tk.Button(btn_frame, text="取消", command=manage_win.destroy, bg=CANCEL_BG, fg='white',
                 font=('微软雅黑', 10, 'bold'), relief='flat', padx=30, pady=8,
                 cursor='hand2').pack(side='left', padx=8)
    
    def mark_todo_done_by_name(self, task_name):
        todos = self.load_todos()
        for todo in todos:
            if task_name in todo['task'] and not todo['done']:
                todo['done'] = True
                self.save_todos(todos)
                return True
        return False

    # ==================== 换皮肤功能 ====================
    
    def get_available_skins(self):
        skins = []
        if os.path.exists(ASSETS_DIR):
            for f in os.listdir(ASSETS_DIR):
                if f.lower().endswith(('.gif', '.png')):
                    skins.append(f)
        return sorted(skins)
    
    def change_skin(self, skin_name):
        self.root.withdraw()
        def apply():
            self.current_skin = skin_name
            self.load_gif(os.path.join(ASSETS_DIR, skin_name))
            self.current_frame = 0
            self.root.deiconify()
            self.show_bubble(f"皮肤已切换为：{skin_name} ✨", 3000)
        self.root.after(100, apply)
    
    def show_skin_selector(self):
        skins = self.get_available_skins()
        if not skins:
            self.show_bubble("暂无皮肤可用，请在assets文件夹中放入GIF/PNG图片～", 5000)
            return
        
        skin_win = tk.Toplevel(self.root)
        skin_win.overrideredirect(True)
        skin_win.attributes('-topmost', True)
        skin_win.config(bg=WINDOW_BG)
        
        win_x, win_y = self.get_safe_window_position(400, 450)
        skin_win.geometry(f'400x450+{win_x}+{win_y}')
        
        shadow = tk.Frame(skin_win, bg='#d0d0d0')
        shadow.pack(fill='both', expand=True, padx=3, pady=3)
        main_frame = tk.Frame(shadow, bg=WINDOW_BG)
        main_frame.pack(fill='both', expand=True)
        
        title_frame = tk.Frame(main_frame, bg=TITLE_BG, height=40)
        title_frame.pack(fill='x')
        title_frame.pack_propagate(False)
        tk.Label(title_frame, text="🎨 选择你的桌宠皮肤", bg=TITLE_BG, fg=TITLE_FG,
                font=('微软雅黑', 11, 'bold')).pack(side='left', padx=15, pady=10)
        
        close_btn = tk.Button(title_frame, text="✕", bg=TITLE_BG, fg=TITLE_FG, relief='flat',
                             font=('微软雅黑', 12, 'bold'), cursor='hand2')
        close_btn.pack(side='right', padx=10)
        
        tk.Label(main_frame, text="💡 添加新皮肤：将GIF/PNG文件放入 assets 文件夹", 
                bg=WINDOW_BG, fg='#757575', font=('微软雅黑', 8)).pack(pady=10)
        
        list_frame = tk.Frame(main_frame, bg=WINDOW_BG)
        list_frame.pack(pady=10, padx=20, fill='both', expand=True)
        
        canvas = tk.Canvas(list_frame, bg=INPUT_BG, relief='solid', borderwidth=1, highlightthickness=0)
        scrollbar = Scrollbar(list_frame, orient='vertical', command=canvas.yview)
        scrollable_frame = tk.Frame(canvas, bg=INPUT_BG)
        scrollable_frame.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
        canvas.create_window((0, 0), window=scrollable_frame, anchor='nw')
        canvas.configure(yscrollcommand=scrollbar.set)
        
        def on_mousewheel(event):
            canvas.yview_scroll(int(-1*(event.delta/120)), "units")
        canvas.bind_all("<MouseWheel>", on_mousewheel)
        
        def on_close():
            canvas.unbind_all("<MouseWheel>")
            skin_win.destroy()
        
        close_btn.config(command=on_close)
        canvas.pack(side='left', fill='both', expand=True)
        scrollbar.pack(side='right', fill='y')
        
        for skin in skins:
            skin_path = os.path.join(ASSETS_DIR, skin)
            item_frame = tk.Frame(scrollable_frame, bg=INPUT_BG)
            item_frame.pack(fill='x', padx=10, pady=8)
            
            try:
                img = Image.open(skin_path)
                if skin.lower().endswith('.gif'):
                    img.seek(0)
                img.thumbnail((80, 80), Image.Resampling.LANCZOS)
                photo = ImageTk.PhotoImage(img)
                
                thumb = tk.Label(item_frame, image=photo, bg=INPUT_BG, relief='solid', borderwidth=1)
                thumb.image = photo
                thumb.pack(side='left', padx=10)
                
                info = tk.Frame(item_frame, bg=INPUT_BG)
                info.pack(side='left', fill='both', expand=True, padx=10)
                tk.Label(info, text=skin, bg=INPUT_BG, fg='#424242', 
                        font=('微软雅黑', 10)).pack(anchor='w', pady=5)
                
                if skin == self.current_skin:
                    tk.Label(info, text="✓ 当前使用", bg=INPUT_BG, fg=SUCCESS_BG,
                            font=('微软雅黑', 9, 'bold')).pack(anchor='w')
                else:
                    tk.Button(info, text="使用此皮肤", bg=BUTTON_BG, fg='white',
                             font=('微软雅黑', 9), relief='flat', padx=15, pady=3, cursor='hand2',
                             command=lambda s=skin: [self.change_skin(s), on_close()]).pack(anchor='w', pady=3)
                    thumb.config(cursor='hand2')
                    thumb.bind('<Button-1>', lambda e, s=skin: [self.change_skin(s), on_close()])
            except Exception as e:
                tk.Label(item_frame, text=f"❌ {skin}", bg=INPUT_BG, fg='#e57373',
                        font=('微软雅黑', 9)).pack(padx=10, pady=5)

    # ==================== 放松游戏 ====================
    
    def start_game(self):
        print("游戏开始！点击桌宠来放松一下吧~")
        self.in_game = True
        self.game_start_time = time.time()
        self.velocity_x = random.choice([-MOVE_SPEED, MOVE_SPEED])
        self.velocity_y = random.choice([-MOVE_SPEED, MOVE_SPEED])
        self.game_move()
    
    def game_move(self):
        if not self.in_game:
            return
        if time.time() - self.game_start_time >= GAME_TIME:
            self.end_game()
            return
        
        x = self.root.winfo_x()
        y = self.root.winfo_y()
        width = self.root.winfo_width()
        height = self.root.winfo_height()
        
        # 随机扰动让路线更自然
        if random.random() < 0.3:
            self.velocity_x += random.uniform(-0.5, 0.5)
            self.velocity_y += random.uniform(-0.5, 0.5)
            max_s, min_s = MOVE_SPEED * 1.5, MOVE_SPEED * 0.5
            if abs(self.velocity_x) > max_s:
                self.velocity_x = max_s if self.velocity_x > 0 else -max_s
            elif abs(self.velocity_x) < min_s:
                self.velocity_x = min_s if self.velocity_x > 0 else -min_s
            if abs(self.velocity_y) > max_s:
                self.velocity_y = max_s if self.velocity_y > 0 else -max_s
            elif abs(self.velocity_y) < min_s:
                self.velocity_y = min_s if self.velocity_y > 0 else -min_s
        
        x += self.velocity_x
        y += self.velocity_y
        
        if x <= 0 or x + width >= self.screen_width:
            self.velocity_x = -self.velocity_x
            x = max(0, min(x, self.screen_width - width))
        if y <= 0 or y + height >= self.screen_height:
            self.velocity_y = -self.velocity_y
            y = max(0, min(y, self.screen_height - height))
        
        self.root.geometry(f'+{int(x)}+{int(y)}')
        self.game_move_id = self.root.after(MOVE_INTERVAL, self.game_move)
    
    def on_click_in_game(self):
        self.root.withdraw()
        self.root.after(1000, self.respawn_random)
    
    def respawn_random(self):
        if not self.in_game:
            return
        new_x = random.randint(0, max(0, self.screen_width - 200))
        new_y = random.randint(0, max(0, self.screen_height - 200))
        self.root.geometry(f'+{new_x}+{new_y}')
        self.root.deiconify()
    
    def end_game(self):
        print("游戏结束！恢复正常模式")
        self.in_game = False
        if self.game_move_id:
            self.root.after_cancel(self.game_move_id)
            self.game_move_id = None
        self.show_bubble(random.choice(CARE_MESSAGES), 6000)
        self.timer.reset()
        self.timer.start()
        self.timer.check_time(self.root)
    
    def run(self):
        self.root.mainloop()


if __name__ == "__main__":
    pet = DesktopPet()
    pet.run()
